using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.Reflection;

[CustomEditor(typeof(Ferr2D_Path))]
public class Ferr2D_PathEditor : Editor {
    Texture2D texMinus   = AssetDatabase.LoadAssetAtPath("Assets/Ferr/Gizmos/dot-minus.png", typeof(Texture2D)) as Texture2D;
    Texture2D texDot     = AssetDatabase.LoadAssetAtPath("Assets/Ferr/Gizmos/dot.png",       typeof(Texture2D)) as Texture2D;
    Texture2D texDotPlus = AssetDatabase.LoadAssetAtPath("Assets/Ferr/Gizmos/dot-plus.png",  typeof(Texture2D)) as Texture2D;

    public static Vector3 offset = new Vector3(0, 0, -0.0f);
    bool showVerts = false;

	void                 OnSceneGUI    () {
        Undo.SetSnapshotTarget(target, "Modified Path");

		Ferr2D_Path  path      = (Ferr2D_Path)target;
        GUIStyle      iconStyle = new GUIStyle();
        iconStyle.alignment     = TextAnchor.MiddleCenter;

        // draw and interact with all the path handles
        DoHandles(path, iconStyle);

        // draw the path line
        DoPath(path);
		
        // do adding verts in when the shift key is down!
		if (Event.current.shift) {
            DoShiftAdd(path, iconStyle);
		}
		
		// update everything that relies on this path, if the GUI changed
		if (GUI.changed) {
            EditorUtility.SetDirty (target);
            path.UpdateDependants();
		}

        // if this was an undo, refresh stuff too
        if (Event.current.type == EventType.ValidateCommand)
        {
            switch (Event.current.commandName)
            {
                case "UndoRedoPerformed":
                    path.UpdateDependants();
                    break;
            }
        }
	}

    private void DoHandles (Ferr2D_Path path, GUIStyle iconStyle)
    {
        Handles.color = new Color(1, 1, 1, 0);
        for (int i = 0; i < path.pathVerts.Count; i++)
        {
            Vector3 pos = path.transform.position + new Vector3(path.pathVerts[i].x, path.pathVerts[i].y, 0);

            // check if we want to remove points
            if (Event.current.control)
            {
                if (Handles.Button(pos + offset, Quaternion.identity, 0.6f, 0.6f, Handles.CircleCap))
                {
                    path.pathVerts.RemoveAt(i);
                    i--;
                    GUI.changed = true;
                }
                if (SetScale(pos + offset, texMinus, ref iconStyle)) Handles.Label(pos + offset, new GUIContent(texMinus), iconStyle);
            }
            else
            {
                // check for moving the point
                if (SetScale(pos + offset, texMinus, ref iconStyle)) Handles.Label(pos + offset, new GUIContent(texDot), iconStyle);
                Vector3 result = Handles.FreeMoveHandle(
                    pos + offset,
                    Quaternion.identity,
                    0.6f,
                    Vector3.zero, Handles.CircleCap);

                path.pathVerts[i] = new Vector2(
                    result.x - path.transform.position.x,
                    result.y - path.transform.position.y);

                // make sure we can add new point at the midpoints!
                if (i + 1 < path.pathVerts.Count || path.closed == true)
                {
                    int index = path.closed && i + 1 == path.pathVerts.Count ? 0 : i + 1;
                    Vector3 pos2 = path.transform.position + new Vector3(path.pathVerts[index].x, path.pathVerts[index].y, 0);
                    Vector3 mid = (pos + pos2) / 2;

                    if (Handles.Button(mid + offset, Quaternion.identity, 0.4f, 0.4f, Handles.CircleCap))
                    {
                        path.pathVerts.Insert(index, new Vector2(mid.x - path.transform.position.x, mid.y - path.transform.position.y));
                    }
                    if (SetScale(mid + offset, texDotPlus, ref iconStyle)) Handles.Label(mid + offset, new GUIContent(texDotPlus), iconStyle);
                }
            }
        }
    }
    private void DoShiftAdd(Ferr2D_Path path, GUIStyle iconStyle)
    {
        Vector2 pos = GetMousePos(Event.current.mousePosition, path.transform.position.z) - new Vector2(path.transform.position.x, path.transform.position.y);

        int closestID = path.GetClosestSeg(pos);
        int secondID  = closestID + 1 >= path.Count ? 0 : closestID + 1;

        float firstDist  = Vector2.Distance(pos, path.pathVerts[closestID]);
        float secondDist = Vector2.Distance(pos, path.pathVerts[secondID]);

        Handles.color = Color.white;
        if (!(secondID == 0 && !path.closed && firstDist > secondDist))
        {
            Handles.DrawLine(
                path.transform.position + new Vector3(pos.x, pos.y, 0),
                path.transform.position + new Vector3(path.pathVerts[closestID].x, path.pathVerts[closestID].y, 0));
        }
        if (!(secondID == 0 && !path.closed && firstDist < secondDist))
        {
            Handles.DrawLine(
                path.transform.position + new Vector3(pos.x, pos.y, 0),
                path.transform.position + new Vector3(path.pathVerts[secondID].x, path.pathVerts[secondID].y, 0));
        }
        Handles.color = new Color(1, 1, 1, 0);

        if (Handles.Button(new Vector3(pos.x, pos.y, 0) + path.transform.position + offset, Quaternion.identity, 0.4f, 0.4f, Handles.CircleCap))
        {
            if (secondID == 0)
            {
                if (firstDist < secondDist)
                {
                    path.pathVerts.Add(new Vector2(pos.x, pos.y));
                }
                else
                {
                    path.pathVerts.Insert(0, new Vector2(pos.x, pos.y));
                }
            }
            else
            {
                path.pathVerts.Insert(Mathf.Max(closestID, secondID), new Vector2(pos.x, pos.y));
            }
            GUI.changed = true;
        }
        if (SetScale(new Vector3(pos.x, pos.y, 0) + path.transform.position + offset, texDotPlus, ref iconStyle)) Handles.Label(new Vector3(pos.x, pos.y, 0) + path.transform.position + offset, new GUIContent(texDotPlus), iconStyle);
    }
    private void DoPath    (Ferr2D_Path path)
    {
        Handles.color = Color.white;
        Ferr2DT_PathTerrain terrain = path.gameObject.GetComponent<Ferr2DT_PathTerrain>();
        List<Vector2> verts = terrain == null ? path.GetVertsRaw() : path.GetVerts(terrain.smoothPath, terrain.splitDist, terrain.splitCorners);
        for (int i = 0; i < verts.Count - 1; i++)
        {
            Vector3 pos  = path.transform.position + new Vector3(verts[i].x, verts[i].y, 0);
            Vector3 pos2 = path.transform.position + new Vector3(verts[i + 1].x, verts[i + 1].y, 0);
            Handles.DrawLine(pos + offset, pos2 + offset);
        }
        if (path.closed)
        {
            Vector3 pos  = path.transform.position + new Vector3(verts[0].x, verts[0].y, 0);
            Vector3 pos2 = path.transform.position + new Vector3(verts[verts.Count - 1].x, verts[verts.Count - 1].y, 0);
            Handles.DrawLine(pos + offset, pos2 + offset);
        }
    }

	public override void OnInspectorGUI() {
        Undo.SetSnapshotTarget(target, "Modified Path");

        Ferr2D_Path path = (Ferr2D_Path)target;

        path.closed = EditorGUILayout.Toggle ("Closed", path.closed);

        // display the path verts list info
        showVerts   = EditorGUILayout.Foldout(showVerts, "Path Vertices");
        EditorGUI.indentLevel = 2;
        if (showVerts)
        {
            int size = EditorGUILayout.IntField("Count: ", path.pathVerts.Count);
            while (path.pathVerts.Count > size) path.pathVerts.RemoveAt(path.pathVerts.Count - 1);
            while (path.pathVerts.Count < size) path.pathVerts.Add     (new Vector2(0, 0));
        }
        // draw all the verts! Long list~
        for (int i = 0; showVerts && i < path.pathVerts.Count; i++)
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("#" + i, GUILayout.Width(60));
            path.pathVerts[i] = new Vector2(
                EditorGUILayout.FloatField(path.pathVerts[i].x),
                EditorGUILayout.FloatField(path.pathVerts[i].y));
            EditorGUILayout.EndHorizontal();
        }

        // button for updating the origin of the object
        if (GUILayout.Button("Center Position")) path.ReCenter();

        // update dependants when it changes
        if (GUI.changed)
        {
			Ferr2DT_PathTerrain terrain = path.GetComponent<Ferr2DT_PathTerrain>();
			if (!path.closed && terrain != null && (terrain.fill == Ferr2DT_FillMode.Closed || terrain.fill == Ferr2DT_FillMode.InvertedClosed)) 
					path.closed = true;
            EditorUtility.SetDirty(target);
            path.UpdateDependants();
        }
	}

	public Vector2 GetMousePos  (Vector2 aMousePos, float aZOffset) {
		
		//aMousePos.y = Screen.height - (aMousePos.y + 25);
		Ray   ray   = SceneView.lastActiveSceneView.camera.ScreenPointToRay(new Vector3(aMousePos.x, aMousePos.y, 0));
		Plane plane = new Plane(new Vector3(0,0,-1), aZOffset);
		float dist  = 0;
		Vector3 result = new Vector3(0,0,0);
		
		ray = HandleUtility.GUIPointToWorldRay(aMousePos);
		if (plane.Raycast(ray, out dist)) {
			result = ray.GetPoint(dist);
		}
		return new Vector2(result.x, result.y);
	}
    public float   GetCameraDist(Vector3 aPt)
    {
        return Vector3.Distance(SceneView.lastActiveSceneView.camera.transform.position, aPt);
    }
    public bool    SetScale     (Vector3 aPos, Texture aIcon, ref GUIStyle aStyle)
    {
        if (Vector3.Dot(SceneView.lastActiveSceneView.camera.transform.forward, aPos - SceneView.lastActiveSceneView.camera.transform.position) > 0)
        {
            float max  = (SceneView.lastActiveSceneView.camera.GetScreenWidth() + SceneView.lastActiveSceneView.camera.GetScreenHeight()) / 2;
            float dist = GetCameraDist(aPos);

            aStyle.fixedWidth = aIcon.width / (dist / (max / 160));
            aStyle.fixedHeight = aIcon.height / (dist / (max / 160));

            return true;
        }
        return false;
    }
}